home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / server_connect.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  13KB  |  464 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.
  4.  
  5.    $Id: server_connect.c,v 1.72 2001/02/15 08:39:45 drscholl Exp $ */
  6.  
  7. /* Modified 30/05/01 : Added include "confdefs.h" since we are not using the
  8.       for Amiga port : CONFIGURE script
  9. */
  10.  
  11. #include "confdefs.h"
  12.  
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include <arpa/inet.h>
  17. #ifndef WIN32
  18. #include <unistd.h>
  19. #endif
  20. #include "opennap.h"
  21. #include "debug.h"
  22.  
  23. static void
  24. try_connect (server_auth_t * auth)
  25. {
  26.     int     f;
  27.     CONNECTION *cli;
  28.     unsigned int ip;
  29.  
  30.     /* attempt a connection.  we do this nonblocking so that the server
  31.        doesn't halt if it takes a long time to connect */
  32.     f = make_tcp_connection (auth->name, auth->port, &ip);
  33.     if (f == -1)
  34.         return;
  35.  
  36.     cli = new_connection ();
  37.     if (!cli)
  38.         goto error;
  39.     cli->fd = f;
  40.     cli->host = STRDUP (auth->alias ? auth->alias : auth->name);
  41.     if (!cli->host)
  42.     {
  43.         OUTOFMEMORY ("try_connect");
  44.         goto error;
  45.     }
  46.     cli->server_login = 1;
  47.     if ((cli->opt.auth = CALLOC (1, sizeof (AUTH))) == 0)
  48.     {
  49.         OUTOFMEMORY ("try_connect");
  50.         goto error;
  51.     }
  52.     cli->opt.auth->nonce = generate_nonce ();
  53.     if (!cli->opt.auth->nonce)
  54.     {
  55.         log ("try_connect: could not generate nonce, closing connection");
  56.         goto error;
  57.     }
  58.     cli->ip = BSWAP32 (ip);
  59.     cli->port = auth->port;
  60.  
  61.     if (add_client (cli, 1/* server connection */))
  62.         goto error;
  63.  
  64.     return;
  65.   error:
  66.     log ("try_connect: closing connection");
  67.     if (cli)
  68.     {
  69.         CLOSE (cli->fd);
  70.         if (cli->host)
  71.             FREE (cli->host);
  72.         if (cli->opt.auth)
  73.         {
  74.             if (cli->opt.auth->nonce)
  75.                 FREE (cli->opt.auth->nonce);
  76.             FREE (cli->opt.auth);
  77.         }
  78.         FREE (cli);
  79.     }
  80. }
  81.  
  82. void
  83. complete_connect (CONNECTION * con)
  84. {
  85.     /* a previous call to read() may have reset the error code */
  86.     if (con->destroy || check_connect_status (con->fd) != 0)
  87.     {
  88.         notify_mods (SERVERLOG_MODE, "Server link to %s failed", con->host);
  89.         destroy_connection (con);
  90.         return;
  91.     }
  92.     con->connecting = 0;        /* connected now */
  93.  
  94.     /* clear the write bit and check the read bit */
  95.     clear_write (con->fd);
  96.     set_read (con->fd);
  97.  
  98.     /* send the login request */
  99.     ASSERT (Server_Name != 0);
  100.     ASSERT (con->server_login == 1);
  101.     ASSERT (con->opt.auth != 0);
  102.     send_cmd (con, MSG_SERVER_LOGIN, "%s %s %d", Server_Name,
  103.               con->opt.auth->nonce, Compression_Level);
  104.  
  105.     /* we handle the response to the login request in the main event loop so
  106.        that we don't block while waiting for th reply.  if the server does
  107.        not accept our connection it will just drop it and we will detect
  108.        it by the normal means that every other connection is checked */
  109.  
  110.     log ("complete_connect: connection to %s established", con->host);
  111. }
  112.  
  113. server_auth_t *
  114. find_server_auth (const char *host)
  115. {
  116.     LIST   *list;
  117.     server_auth_t *auth;
  118.  
  119.     for (list = Server_Auth; list; list = list->next)
  120.     {
  121.         auth = list->data;
  122.         if (!strcasecmp (host, auth->name) ||
  123.             (auth->alias && !strcasecmp (host, auth->alias)))
  124.             return auth;
  125.     }
  126.     return 0;
  127. }
  128.  
  129. /* process client request to link another server
  130.  * 10100 [ :<user> ] <server-name> [remote_server]
  131.  */
  132. HANDLER (server_connect)
  133. {
  134.     USER   *user;
  135.     char   *av[3];
  136.     char   *remote_server = Server_Name;
  137.     char   *sender_name;
  138.     int     ac;
  139.     server_auth_t *auth = 0;
  140.  
  141.     (void) tag;
  142.     (void) len;
  143.     ASSERT (validate_connection (con));
  144.     if (pop_user_server (con, tag, &pkt, &sender_name, &user) != 0)
  145.         return;
  146.     ASSERT (validate_user (user));
  147.  
  148.     if (user->level < LEVEL_ADMIN)
  149.     {
  150.         log ("server_connect: failed request from %s", user->nick);
  151.         send_user (user, MSG_SERVER_NOSUCH,
  152.                    "[%s] server connect failed: permission denied",
  153.                    Server_Name);
  154.         return;                 /* no privilege */
  155.     }
  156.  
  157.     ac = split_line (av, FIELDS (av), pkt);
  158.  
  159.     if (ac < 1)
  160.     {
  161.         log ("server_connect: too few parameters");
  162.         send_user (user, MSG_SERVER_NOSUCH,
  163.                    "[%s] server connect failed: missing parameter",
  164.                    Server_Name);
  165.         return;
  166.     }
  167.  
  168.     /* check to make sure this server is not already linked */
  169.     if (is_linked (av[0]))
  170.     {
  171.         send_user (user, MSG_SERVER_NOSUCH,
  172.                    "[%s] server connect failed: already linked", Server_Name);
  173.         return;
  174.     }
  175.  
  176.     /* check to see if a remote server was specified.  otherwise we assume
  177.      * link from the local server
  178.      */
  179.     if (ac > 1)
  180.         remote_server = av[1];
  181.  
  182.     /* determine if the link is supposed to be made from this server */
  183.     if (!strcasecmp (remote_server, Server_Name))
  184.     {
  185.         /* look up the server auth info to find out if we are allowed to
  186.          * link this server
  187.          */
  188.         auth = find_server_auth (av[0]);
  189.  
  190.         /* if there is no server, or the user attempted to connect the server
  191.          * by its real name and there is a nick defined, report an error.
  192.          */
  193.         if (!auth || (auth->alias && !strcasecmp (av[0], auth->name)))
  194.         {
  195.             send_user (user, MSG_SERVER_NOSUCH,
  196.                        "[%s] server connect failed: no such server",
  197.                        Server_Name);
  198.             return;
  199.         }
  200.  
  201.         /* check to make sure this server isn't linked.  we use the real name
  202.          * of the server here just because the above check might have been
  203.          * the nick of the server.
  204.          */
  205.         if (is_linked (auth->name))
  206.         {
  207.             send_user (user, MSG_SERVER_NOSUCH,
  208.                        "server connect failed: %s is already linked",
  209.                        auth->alias ? auth->alias : auth->name);
  210.             return;
  211.         }
  212.  
  213.         /* use the real name when we connect */
  214.         try_connect (auth);
  215.  
  216.         /* ugh, this has to be here to prevent disclosure of the real dns name
  217.          * of an aliased server.  unfortunately it means that only the server
  218.          * where the link is being made from will see this, but if someone
  219.          * tries to remote connect an aliased server via its real dns name,
  220.          * it would be displayed to all mods+ along the line.
  221.          */
  222.         notify_mods (SERVERLOG_MODE,
  223.                      "%s requested server link from %s to %s:%hu",
  224.                      user->nick, remote_server,
  225.                      /* don't use the real name if the server has a nick */
  226.                      auth->alias ? auth->alias : auth->name, auth->port);
  227.     }
  228.     else if (!is_linked (remote_server))
  229.     {
  230.         send_user (user, MSG_SERVER_NOSUCH,
  231.                    "[%s] server connect failed: no such remote server",
  232.                    Server_Name);
  233.         return;
  234.     }
  235.     else
  236.     {
  237.         ASSERT (remote_server != Server_Name);
  238.  
  239.         pass_message_args (con, MSG_CLIENT_CONNECT, ":%s %s %s",
  240.                            user->nick, av[0], remote_server);
  241.     }
  242. }
  243.  
  244. /* 10101 [ :<nick> ] <server> ["reason"]
  245.  * server disconnect/quit notification
  246.  */
  247. HANDLER (server_disconnect)
  248. {
  249.     USER   *user;
  250.     char   *sender_name;
  251.     int     ac = -1;
  252.     char   *av[2];
  253.     LIST   *list;
  254.     CONNECTION *serv;
  255.  
  256.     (void) tag;
  257.     (void) len;
  258.     ASSERT (validate_connection (con));
  259.     if (pop_user_server (con, tag, &pkt, &sender_name, &user) != 0)
  260.         return;
  261.     if (pkt)
  262.         ac = split_line (av, FIELDS (av), pkt);
  263.     if (ac < 1)
  264.     {
  265.         unparsable (con);
  266.         return;
  267.     }
  268.  
  269.     if (user)
  270.     {
  271.         ASSERT (validate_user (user));
  272.         if (user->level < LEVEL_ADMIN)
  273.         {
  274.             if (ISUSER (con))
  275.                 send_cmd (con, MSG_SERVER_NOSUCH,
  276.                           "server disconnect failed: permission denied");
  277.             return;
  278.         }
  279.     }
  280.  
  281.     if (!is_linked (av[0]))
  282.     {
  283.         if (user && ISUSER (user->con))
  284.             send_user (user, MSG_SERVER_NOSUCH,
  285.                     "server disconnect failed: no such server");
  286.         else
  287.             log("server_disconnect: %s is not linked", av[0]);
  288.         return;
  289.     }
  290.  
  291.     /* if the server is locally connected, mark it for disconnection */
  292.     for (list = Servers; list; list = list->next)
  293.     {
  294.         serv = list->data;
  295.         if (!strcasecmp (av[0], serv->host))
  296.         {
  297.             serv->quit = 1;     /* note that we received a quit message */
  298.             destroy_connection (serv);
  299.             break;
  300.         }
  301.     }
  302.  
  303.     pass_message_args (con, MSG_CLIENT_DISCONNECT, ":%s %s \"%s\"",
  304.                        sender_name, av[0], (ac > 1) ? av[1] : "");
  305.  
  306.     /* remove all links behind this server */
  307.     remove_links (av[0]);
  308.  
  309.     notify_mods (SERVERLOG_MODE, "Server %s has quit: %s (%s)",
  310.             av[0], (ac > 1) ? av[1] : "", sender_name);
  311. }
  312.  
  313. /* 10110 [ :<user> ] <server> [ "<reason>" ] */
  314. /* force the server process to die */
  315. HANDLER (kill_server)
  316. {
  317.     USER   *user;
  318.     int     ac = -1;
  319.     char   *av[2];
  320.  
  321.     (void) tag;
  322.     (void) len;
  323.     ASSERT (validate_connection (con));
  324.     ASSERT (pkt != 0);
  325.     if (pop_user (con, &pkt, &user) != 0)
  326.         return;
  327.     if (pkt)
  328.         ac = split_line (av, FIELDS (av), pkt);
  329.     if (ac < 1)
  330.     {
  331.         unparsable (con);
  332.         return;
  333.     }
  334.     ASSERT (validate_user (user));
  335.     if (user->level < LEVEL_ELITE)
  336.     {
  337.         permission_denied (con);
  338.         return;
  339.     }
  340.  
  341.     if (!is_linked (av[0]) && strcasecmp (Server_Name, av[0]) != 0)
  342.     {
  343.         send_user (user, MSG_SERVER_NOSUCH,
  344.                    "kill server failed: no such server");
  345.         return;
  346.     }
  347.  
  348.     if (ac > 1)
  349.         truncate_reason (av[1]);
  350.  
  351.     pass_message_args (con, MSG_CLIENT_KILL_SERVER, ":%s %s \"%s\"",
  352.                        user->nick, av[0], (ac > 1) ? av[1] : "");
  353.  
  354.     notify_mods (SERVERLOG_MODE, "%s killed server %s: %s", user->nick,
  355.                  av[0], (ac > 1) ? av[1] : "");
  356.  
  357.     if (!strcasecmp (av[0], Server_Name))
  358.     {
  359.         log ("kill_server(): shutdown by %s: %s", user->nick,
  360.              (ac > 1) ? av[1] : "");
  361.         SigCaught = 1;          /* this causes the main event loop to exit */
  362.     }
  363. }
  364.  
  365. /* 10111 <server> [ <reason> ] */
  366. HANDLER (remove_server)
  367. {
  368.     char   *reason;
  369.  
  370.     (void) tag;
  371.     (void) len;
  372.     ASSERT (validate_connection (con));
  373.     /* TODO: should we be able to remove any server, or just from the local
  374.        server? */
  375.     CHECK_USER_CLASS ("remove_server");
  376.     ASSERT (validate_user (con->user));
  377.     if (con->user->level < LEVEL_ELITE)
  378.     {
  379.         permission_denied (con);
  380.         return;
  381.     }
  382.     reason = strchr (pkt, ' ');
  383.     if (reason)
  384.         *reason++ = 0;
  385.     snprintf (Buf, sizeof (Buf), "DELETE FROM servers WHERE server = '%s'",
  386.               pkt);
  387. }
  388.  
  389. /* 801 [ :<user> ] [ <server> ] */
  390. HANDLER (server_version)
  391. {
  392.     USER   *user;
  393.  
  394.     (void) tag;
  395.     (void) len;
  396.     ASSERT (validate_connection (con));
  397.     if (pop_user (con, &pkt, &user) != 0)
  398.         return;
  399.     ASSERT (validate_user (user));
  400.     if (user->level < LEVEL_MODERATOR)
  401.     {
  402.         if (con->class == CLASS_USER)
  403.             permission_denied (con);
  404.         return;
  405.     }
  406.     if (!*pkt || !strcmp (Server_Name, pkt))
  407.     {
  408.         send_user (user, MSG_SERVER_NOSUCH, "--");
  409.         send_user (user, MSG_SERVER_NOSUCH, "%s %s", PACKAGE, VERSION);
  410.         send_user (user, MSG_SERVER_NOSUCH, "--");
  411.     }
  412.     else
  413.         pass_message_args (con, tag, ":%s %s", user->nick, pkt);
  414. }
  415.  
  416. /* 0/404 <message> */
  417. HANDLER (server_error)
  418. {
  419.     (void) tag;
  420.     (void) len;
  421.     ASSERT (validate_connection (con));
  422.     CHECK_SERVER_CLASS ("server_error");
  423.     notify_mods (ERROR_MODE, "Server %s sent error: %s", con->host, pkt);
  424. }
  425.  
  426. int
  427. is_linked (const char *host)
  428. {
  429.     LIST   *list;
  430.     LINK   *link;
  431.     CONNECTION *serv;
  432.  
  433.     if (!strcasecmp (host, Server_Name))
  434.         return 1;               /* self */
  435.  
  436.     /* check local links */
  437.     for (list = Servers; list; list = list->next)
  438.     {
  439.         serv = list->data;
  440.         if (!strcasecmp (serv->host, host))
  441.             return 1;
  442.     }
  443.  
  444.     /* check remote links */
  445.     for (list = Server_Links; list; list = list->next)
  446.     {
  447.         link = list->data;
  448.         if (!strcasecmp (link->server, host)
  449.             || !strcasecmp (link->peer, host))
  450.             return 1;
  451.     }
  452.     return 0;
  453. }
  454.  
  455. /* auto link our servers */
  456. void
  457. auto_link (void)
  458. {
  459.     LIST   *list;
  460.  
  461.     for (list = Server_Auth; list; list = list->next)
  462.         try_connect (list->data);
  463. }
  464.